//***********************************************************************
//	File:		Moveable.cpp
//	Author:		
//	Course:		SGP 1405
//	Purpose:	
//***********************************************************************
//***********************************************************************
//	Purposfully left blank for all comments regarding this file 
//	
//	
//	
//***********************************************************************

#include <math.h>
#include "Moveable.h"
#include "../ParticleSystem/Emitter.h"
#include "../TileSystem/TileSystem.h"


void Moveable::Update(float dt)
{
	// Compute object speed, that is the norm of the velocity
	m_fSpeed = m_vVelocity.ComputeLength();

	// Compute the aerodynamic drag force
	m_vDragForce = m_vVelocity * (-.5f * m_fSpeed * m_fDragCoefficient * ( m_szSize.width / 64));
	// Apply Friction
	ApplyFriction(dt);
	// Compute the acceleration using Newton's 2nd Law
	m_vAcceleration = m_vTotalForces / m_fMass;
	// Compute the velocity
	m_vVelocity += m_vAcceleration * dt;

	// Update the position
	SGD::Rectangle projected = GetRect();
	projected.left += m_vVelocity.x*dt;
	projected.right += m_vVelocity.x*dt;
	
	if ( TILESYSTEM->CheckWorld ( projected ) == SGD::Rectangle {0.0f, 0.0f, 0.0f, 0.0f} )
		m_ptPosition.x += m_vVelocity.x * dt;

	projected = GetRect();
	projected.top += m_vVelocity.y*dt;
	projected.bottom += m_vVelocity.y*dt;
	if ( TILESYSTEM->CheckWorld ( projected ) == SGD::Rectangle {0.0f, 0.0f, 0.0f, 0.0f} )
		m_ptPosition.y += m_vVelocity.y * dt;
}

void Moveable::Render()
{

}

void Moveable::HandleCollision(const IEntity* pOther)
{

}

void Moveable::HandleEvent()
{

}

SGD::Rectangle Moveable::GetRect() const
{
	SGD::Rectangle rect;
	
	rect.left = m_ptPosition.x - (m_szSize.width  * 0.5f);
	rect.top = m_ptPosition.y - (m_szSize.height  * 0.5f);
	rect.right = rect.left + m_szSize.width;
	rect.bottom = rect.top + m_szSize.height;

	return rect;
}

void Moveable::ModifyHealth(float hpAmount)
{

}

//Will be called inside of Update()  
void Moveable::ApplyFriction(float dt)
{
	float m_fStaticFriction;					// Static Friction
	SGD::Vector m_vKineticFriction;				// Kinetic Friction
	SGD::Vector m_vTangetForce;					// Tangential Component of the applied force
	SGD::Vector m_vTangent;						// Vector in the direction of the tangential component of the applied force

	
	// Compute the tangential component of the applied force
	m_vTangetForce = m_vForce;
	// Compute the tangent vector
	m_vTangent = m_vTangetForce.ComputeNormalized();

	if( m_vVelocity.ComputeLength() == 0.0f)
	{
		// We have static state
		// Compute static friction, see note for formula
		m_fStaticFriction = m_fStaticFrictionCoefficient;
		// Set velocity to (0,0)
		m_vVelocity = SGD::Vector(0,0);
		// Compute the total force applid to the ball
		m_vTotalForces = SGD::Vector(0,0);
	}

	if( m_vVelocity.ComputeLength() > 0.0f)
	{
		// Compute Kinetic friction
		m_vKineticFriction =  m_vVelocity.ComputeNormalized() * (-m_fDynamicFrictionCoefficient);
		// Set the Friction Force equal to the previously computed kinetic friction
		m_vFrictionForce = m_vKineticFriction;
		// Compute the total, including friction and drag force on the object
		m_vTotalForces = m_vForce + m_vFrictionForce + m_vDragForce;
	}

	if(m_vVelocity.ComputeLength() == 0.0f && m_vTangetForce.ComputeLength() >= m_fStaticFriction)
	{
		float m_fSlidingFactor;			// Sliding factor to make the transition from static to dynamic
		// Compute the sliding factor (sliding speed) that is the ration of the tangent force
		m_fSlidingFactor = m_vTangetForce.ComputeLength() / m_fStaticFriction;
		// Compute an initial velocity to break the transition from static friction to dynamic friction
		// that is velocity = sliding factor x direction of action (= direction of tangent force, computed as "tangent")
		m_vVelocity = m_vTangent * m_fSlidingFactor;
		// Compute Kinetic(dynamic) friction
		m_vKineticFriction = m_vVelocity.ComputeNormalized() * (-m_fDynamicFrictionCoefficient);
		// Set friction force equal to dynamic friction computed above
		m_vFrictionForce = m_vKineticFriction;
		// Compute total forces involved
		m_vTotalForces = m_vForce + m_vFrictionForce + m_vDragForce;
	}

	// Clamp velocity by its components to zero

	// If the X component of velocity is 0.1(close to 0), set it to 0
	if(abs(m_vVelocity.x) <= 0.1f)
		m_vVelocity.x = 0.0f;
	// If the Y component of velocity is 0.1(close to 0), set it to 0
	if(abs(m_vVelocity.y) <= 0.1f)
		m_vVelocity.y = 0.0f;

	// Decrease the force with a damping factor
	if(abs(m_vForce.x) > 0.1f)
		m_vForce.x = m_vForce.x * 0.66f;
	else
		m_vForce.x = 0.0f;

	if(abs(m_vForce.y) > 0.1f)
		m_vForce.y = m_vForce.y * 0.66f;
	else
		m_vForce.y = 0.0f;
}

